package com.bigbird.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

import static java.nio.charset.StandardCharsets.UTF_8;

/**
 * 两个线程就能达到多个客户端使用的问题
 * 但是如果这个客户端非常多呢？这个单线程遍历问题还是挺多的，比如经典的C10K问题。下一个版本将继续探讨
 */
public class NioServerV2 {
    private static final List<SocketChannel> socketChannelList=new ArrayList<>();
    public static void main(String[] args) throws IOException {
        try(ServerSocketChannel serverSocketChannel = ServerSocketChannel.open()){
            serverSocketChannel.configureBlocking(false);
            serverSocketChannel.bind(new InetSocketAddress(1881));
            Thread thread = new Thread(() -> {
                while(true) {
                    try {
                        SocketChannel socketChannel = serverSocketChannel.accept();
                        if (null != socketChannel) {
                            System.out.println(socketChannel+" connection");
                            socketChannel.configureBlocking(false);
                            ByteBuffer byteBuffer=ByteBuffer.allocate(20);
                            byteBuffer.put("hello connection".getBytes(UTF_8));
                            socketChannel.write(byteBuffer);
                            synchronized (socketChannelList) {
                                socketChannelList.add(socketChannel);
                            }
                        }
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            });
            thread.start();

            Thread thread2 = new Thread(() -> {
                while(true) {
                    synchronized (socketChannelList) {
                        for (SocketChannel socketChannel : socketChannelList) {
                            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                            try {
                                int ret;
                                int readbyte=0;
                                while ((ret=socketChannel.read(byteBuffer))>0) {
                                    readbyte+=ret;
                                    if(!byteBuffer.hasRemaining()){
                                        break;
                                    }
                                }
                                if(readbyte>0){
                                    byteBuffer.flip();
                                    byte[] bytes=new byte[readbyte];
                                    byteBuffer.get(bytes);
                                    System.out.println("socket:"+socketChannel+"  \r\n message:"+ new String(bytes));
                                    ByteBuffer byteBufferWrite = ByteBuffer.wrap("good job".getBytes(StandardCharsets.UTF_8));
                                    socketChannel.write(byteBufferWrite);
                                    byteBuffer.rewind();
                                }else if(readbyte<0){
                                    socketChannel.socket().close();
                                    socketChannel.close();
                                }
                                byteBuffer.clear();
                            } catch (Exception e) {
                                try {
                                    socketChannel.socket().close();
                                    socketChannel.close();
                                } catch (IOException ignored) {
                                }
                            }
                        }
                    }
                }
            },"channel deal ");
            thread2.start();

            thread2.join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}
